const nsIglNetworkStatus = Components.interfaces.nsIglNetworkStatus;
const nsISupports = Components.interfaces.nsISupports;
const CLASS_ID = Components.ID("{df64a3cf-86fa-44db-9fc7-b8e0d382cd26}");
const CLASS_NAME = "NetworkStatus detecter of Gladder";
const CONTRACT_ID = "@gladder.gneheix.com/NetworkStatus;1";
const CC = Components.classes;
const CI = Components.interfaces;

function NetworkStatus() {
	CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService).addObserver(this, "network:offline-status-changed", false);
    this._ioService = CC["@mozilla.org/network/io-service;1"].createInstance(CI.nsIIOService);
	this._uri = this._ioService.newURI("http://www.baidu.com", null, null);
    this._offline = this._ioService.offline;
	this._observer= new this.observer(this);
    if (this._offline){
    	this._setOnline(false);
    }
	this.asyncTest();
	this._setTimer(0.1);
};

NetworkStatus.prototype = {
	_online: true,
	_offline: false,
	_asyncTesting: false,
	
	get online(){
		this.asyncTest();
		return this._online;
	},
	syncTest: function(){
		try {
			if (this._offline){
				return false;
			}
		    var channel = this._ioService.newChannelFromURI(this._uri).QueryInterface(Components.interfaces.nsIHttpChannel);
			channel.setRequestHeader("Cache-Control", "no-cache", true);
			channel.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT", true);
		    var input = CC["@mozilla.org/scriptableinputstream;1"].createInstance(CI.nsIScriptableInputStream);
		    input.init(channel.open());
		    if (input.available() == 0){
		    	this._setOnline(false);
		    	return false;
		    }
		    input.close();
		    this._setOnline(true);
		    return true;		    
		}
		catch (e){dump("glNetworkStatus synchronizing testing error: "+e+e.description+"\n")}
	    this._setOnline(false);
		return false;
	},
	asyncTest : function () {
		try {
			if (this._offline){
				return;
			}
		    if (this._asyncTesting){
		    	return;
		    }
		    var channel = this._ioService.newChannelFromURI(this._uri).QueryInterface(Components.interfaces.nsIHttpChannel);
			channel.setRequestHeader("Cache-Control", "no-cache", true);
			channel.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT", true);
		    channel.asyncOpen(this._observer, null);
		    this._asyncTesting = true;
		}
		catch (e) {
			dump("glNetworkStatus asynchronizing testing error: "+e+e.description+"\n")
		    this._setOnline(false);
		}
	},
	
	_setOnline: function (online){
		if (this._online != online){
			this._online = online;
			CC["@mozilla.org/observer-service;1"].
				getService(CI.nsIObserverService).
				notifyObservers(this, "gl-network-status", online);	
		}
		CC["@mozilla.org/observer-service;1"].
			getService(CI.nsIObserverService).
			notifyObservers(this, "gl-network-status-testing-result", online);	
	},
  _callback: function(aData, aRequest)
  {
    var network = true;
    try {
	    var httpChannel = aRequest.QueryInterface(CI.nsIHttpChannel);
	    var status = null;
	    var statusText = null;
    
      // Get HTTP response
      status = httpChannel.responseStatus;
      statusText = httpChannel.responseStatusText;
    } catch (e) {
      network = false;
    }
    this._setOnline(network);
  	this._asyncTesting = false;
  },
    _setTimer: function(minutes)
  {
    if (this._timer) {
      this._timer.cancel();
      this._timer = null;
    }
    
    if (minutes > 0) {
      try {
        this._interval = minutes;
        this._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
        this._timer.initWithCallback(this, minutes * 60000, this._timer.TYPE_REPEATING_PRECISE);
      } catch(e) {dump("glNetworkStatus setTimer error: "+e+e.description+"\n")}
    }
  },
	observe: function(aSubject, aTopic, aData){
		if (aTopic == "network:offline-status-changed"){
			try{
				this._offline = aSubject.offline;
				if (aSubject.offline){
					this._setOnline(false);
				}
				else{
					this.asyncTest();
				}
			}catch(e){}
		}
	},
  
  notify: function(aTimer)
  {
  	try{
  		if (this._offline || this._online){
  			return;
  		}
      	this.asyncTest();
  	}
  	catch(e){dump(e+"\n")}
  },
  
  observer: function(aThis)
  {
    return ({
      _myData: "",
      
      onStartRequest: function(aRequest, aContext) {
        this._myData = "";
      },
      
      onStopRequest: function(aRequest, aContext, aStatus) {
        aThis._callback(this._myData, aRequest);
      },
      
      onDataAvailable: function(aRequest, aContext, aStream, aSourceOffset, aLength) {
        var scriptableInputStream = CC["@mozilla.org/scriptableinputstream;1"].createInstance(CI.nsIScriptableInputStream);
        scriptableInputStream.init(aStream);
        this._myData += scriptableInputStream.read(aLength);
      }});
  	},
  
	QueryInterface: function(aIID)
	{
		if (!aIID.equals(nsIglNetworkStatus) &&
		!aIID.equals(nsISupports)&& 
    	!aIID.equals(CI.nsIObserver))
		throw Components.results.NS_ERROR_NO_INTERFACE;
		return this;
	}
};
var NetworkStatusFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new NetworkStatus()).QueryInterface(aIID);
  }
};

var NetworkStatusModule = {
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, 
        CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType)
  {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return NetworkStatusFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};
function NSGetModule(aCompMgr, aFileSpec) { return NetworkStatusModule; }